#pragma once // 负责IO处理
#include <iostream>
#include <cerrno>
#include "connection.hpp"
#include "Protocol.hpp"
#include "Log.hpp"
#include "HandlerRequest.hpp"
#include <sys/types.h>
#include <sys/socket.h>

using namespace Protocol;

class HandlerConnection
{
public:
    static const int buff_size = 1024;
    // ET模式下的读
    static void Reader(Connection::ptr conn)
    {
        errno = 0;
        while (true)
        {
            char buff[buff_size];
            int n = recv(conn->SockFd(), buff, sizeof(buff - 1), 0);
            if (n > 0)
            {
                buff[n] = 0;
                conn->AddInbuffer(buff);
            }
            else
            {
                if (errno == EAGAIN)
                    break;
                else if (errno == EINTR)
                    continue;
                else
                {
                    conn->_excepter(conn);
                    return;
                }
            }
        }
        // 底层数据读取结束, 业务处理
        HandlerRequest handler;
        handler.Handler(conn);
    }
    // 对于发送，是按需关心的,因为大部分时间发送都会成功，当发送缓冲区满了然后再添加关心
    static void Sender(Connection::ptr conn)
    {
        errno = 0;
        std::string &outbuff = conn->Outbuffer();
        while (true)
        {
            int n = send(conn->SockFd(), outbuff.c_str(), outbuff.size(), 0);
            if (n >= 0)
            {
                outbuff.erase(0, n); // 移除发送的数据
                if (conn->OutBufferEmpty())
                {
                    break; // 本轮数据发送完毕
                }
            }
            else
            {
                if (errno == EAGAIN)
                {
                    break; // 发送缓冲区写满
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    conn->_excepter(conn);
                    return;
                }
            }
        }
        // 按需关心，写完即可关闭对EPOLLOUT的关心
        if (conn->OutBufferEmpty())
        {
            conn->_R->EnableReadWrite(conn->SockFd(), true, false);
        }
        else
        {
            conn->_R->EnableReadWrite(conn->SockFd(), true, true);
        }
    }
    static void Excepter(Connection::ptr conn)
    {
        errno = 0;
        lg(Info, "Connection abnormal closure, fd : %d", conn->SockFd());
        // del epoll
        // _conns
        conn->_R->RemoveConnection(conn->SockFd());
        // close(fd)
        conn->Close();
    }
};